#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<signal.h>
#include<sys/wait.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#define BUF_SIZE 100
void error_handling(char *message);
void read_childproc(int sig);
//并发服务器，使用进程间通信将传输的字符串按序保存到文件中
int main(int argc,char *argv[])
{
	int serv_sock,clnt_sock;
	struct sockaddr_in serv_adr,clnt_adr;
	int fds[2];
	
	pid_t pid;
	struct sigaction act;
	socklen_t adr_sz;
	int str_len,state;
	char buf[BUF_SIZE];
	if(argc!=2)
	{
		printf("Usage:%s<port>\n",argv[0]);
		exit(1);
	}
	act.sa_handler=read_childproc;
	sigemptyset(&act.sa_mask);
	act.sa_flags=0;
	state=sigaction(SIGCHLD,&act,0);
	serv_sock=socket(PF_INET,SOCK_STREAM,0);
	memset(&serv_adr,0,sizeof(serv_adr));
	serv_adr.sin_family=AF_INET;
	serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);
	serv_adr.sin_port=htons(atoi(argv[1]));
	if(bind(serv_sock,(struct sockaddr*)&serv_adr,sizeof(serv_adr))==-1)
		error_handling("bind() error");
	if(listen(serv_sock,5)==-1)
		error_handling("listen() error");
	
	pipe(fds);
	pid=fork();
	//这个子进程向管道读取数据后，写入文件中
	if(pid==0)
	{
		FILE *fp=fopen("echomsg.txt","wt");
		char msgbuf[BUF_SIZE];
		int i,len;
		for(i=0;i<10;i++)
		{
			len=read(fds[0],msgbuf,BUF_SIZE);
			fwrite((void*)msgbuf,1,len,fp);
		}
		fclose(fp);
		return 0;
	}
	while(1)
	{
		adr_sz=sizeof(clnt_adr);
		clnt_sock=accept(serv_sock,(struct sockaddr*)&clnt_adr,&adr_sz);
		if(clnt_sock==-1)
			continue;
		else
			puts("new client connected...");
		
		//这个进程向套接字写入数据并向管道写入数据
		pid=fork();
		if(pid==-1)//创建子进程失败，关闭套接字
		{
			close(clnt_sock);
			continue;
		}
		if(pid==0)//子进程
		{
			//套接字属于操作系统
			//子进程也复制了文件描述符，并关联套接字
			//只有所有的文件描述符都关闭了，才能销毁套接字，所以只保持一个文件描述符
			close(serv_sock);//服务器套接字文件描述符同样也传递到子进程
			while((str_len=read(clnt_sock,buf,BUF_SIZE))!=0)
			{
				write(clnt_sock,buf,str_len);
				write(fds[1],buf,str_len);
			}
			close(clnt_sock);
			puts("client disconnected...");
			return 0;
		}
		else
			close(clnt_sock);
	}
	close(serv_sock);	
	return 0;
}
void read_childproc(int sig)
{
	pid_t pid;
	int status;
	pid=waitpid(-1,&status,WNOHANG);
	printf("removed proc id:%d\n",pid);
}
void error_handling(char *message)
{
	fputs(message,stderr);
	fputc('\n',stderr);
	exit(1);
}
